import {
	addIcon, App, HeadingCache, MarkdownView, moment, normalizePath, Notice,
	Plugin, PluginSettingTab, Setting, TFile, TFolder, Vault
} from "obsidian";
import * as Path from "path";
import * as fs from 'fs';
import {exec, ExecException, execFile, spawn, spawnSync} from "child_process";

enum EntryType {
	String,
	ArrayOfString,
	Boolean,
	Number,
	Date,
	TemplateString,
}

class FrontmatterDefinition {
	public name: string;  // NormalNote | HugoNote
	private entryTypeMap: Map<string, EntryType>;
	private defaultValueMap: Map<string, string | Array<string> | boolean | number | Date>

	constructor(name: string) {
		this.name = name;
		this.entryTypeMap = new Map<string, EntryType>();
		this.defaultValueMap = new Map<string, string | Array<string> | boolean | number | Date>();
	}

	public add(key: string, entryType : EntryType, defaultValue: string | Array<string> | boolean | number | Date) {
		this.entryTypeMap.set(key, entryType);
		this.defaultValueMap.set(key, defaultValue);
	}

	public getDefaultValue(key: string) {
		return this.defaultValueMap.get(key);
	}

	public getEntryType(key: string) {
		return this.entryTypeMap.get(key);
	}

	public *iter() {
		for (const entries of this.entryTypeMap.entries()){
			const [key, entryType] = entries;
			const defaultValue = this.defaultValueMap.get(key);
			yield [key, entryType, defaultValue];
		}
	}
}

interface PluginSettings {
	pathNameArray: Array<any>,
	definitionArray: Array<FrontmatterDefinition>,
	definitionNamedJsonTextArray: Array<any>,
	ignoredSuffixArray: Array<string>,
}

const DEFAULT_SETTINGS: PluginSettings = {
	pathNameArray: [
		{pathPrefix: "0_Workshop/", name: null},
		{pathPrefix: "0_Workshop/working/obsidian-frontmatter-manager/", name: "NormalNote"},
		{pathPrefix: "1_Inbox/Diary/", name: null},
		{pathPrefix: "3_Pages/个人博客/", name: "BlogNote"},
		{pathPrefix: "default", name: "NormalNote"},
	],
	// pathNameMap: new Map<string, string>([
	// 		["0_Workshop/", null],
	// 		["1_Inbox/Diary/", null],
	// 		["3_Pages/个人博客/", "BlogNote"],
	// 		["default", "NormalNote"]
	// 	]),
	definitionArray: [],
	definitionNamedJsonTextArray: [],
	ignoredSuffixArray: [".excalidraw.md"]
}

//Add chevron-up-square icon from lucide for mobile toolbar (temporary until Obsidian updates to Lucide v0.130.0)
addIcon("chevron-up-square", `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-up-square"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><polyline points="8,14 12,10 16,14"></polyline></svg>`);

class TemplateString extends String {
	interpolate(params: Object) {
		const names = Object.keys(params);
		const vals = Object.values(params);
		return new Function(...names, `return \`${this}\`;`)(...vals);
	}
}

export default class FrontMatterManagerPlugin extends Plugin {
    settings: PluginSettings;
	modifyFlag: boolean = true;

	getClosestFrontmatterDefinition(path: string): FrontmatterDefinition {
		for (const ignoredSuffix of this.settings.ignoredSuffixArray) {
			if (path.endsWith(ignoredSuffix)) {
				return null;
			}
		}
		this.settings.pathNameArray.sort((a, b) => {
			if (a.pathPrefix.length > b.pathPrefix.length) return -1;
			if (a.pathPrefix.length < b.pathPrefix.length) return 1;
			return 0;
		});
		for (const iter of this.settings.pathNameArray) {
			if (path.startsWith(iter.pathPrefix)){
				if (iter.name) {
					return this.settings.definitionArray.find(obj => obj.name === iter.name);
				}
				else {
					return null;
				}
			}
		}
		const defaultPathName = this.settings.pathNameArray.find(obj => obj.pathPrefix === "default");
		return this.settings.definitionArray.find(obj => obj.name === defaultPathName.name);
	}

    async onload() {
        await this.loadSettings();
		this.app.workspace.onLayoutReady(() => {
			this.registerEvent(this.app.vault.on('create', async (file) => {
				const frontmatterDefinition = this.getClosestFrontmatterDefinition(file.path);
				if (file instanceof TFile && file.extension === "md" && frontmatterDefinition) {
					try {
						if (this.modifyFlag) {
							let frontmatter;
							const existingFrontmatter = await this.getExistingFrontmatter(file);
							const newGeneratedFrontmatter = this.generateNewFrontmatter(file);
							if (existingFrontmatter.size > 0) {
								frontmatter = this.mergeWithFrontmatter(newGeneratedFrontmatter, existingFrontmatter);
							} else {
								frontmatter = newGeneratedFrontmatter;
							}

							for (const [key, value] of frontmatter) {
								if (frontmatterDefinition.getEntryType(key) === EntryType.TemplateString) {
									frontmatter.set(key, new TemplateString(frontmatterDefinition.getDefaultValue(key)).interpolate({
										title: file.basename,
										titleHash: this.generate_random_sha1(file.basename)
									}))
								}
							}

							const modifiedContent = await this.appendToContent(file, frontmatter);
							this.modifyFlag = false;
							await this.app.vault.modify(file, modifiedContent);
							this.modifyFlag = true;
							// if (frontmatter.size <= 0) {
							// 	const newGeneratedFrontmatter = this.generateNewFrontmatter(file);
							// 	const modifiedContent = await this.appendToContent(file, newGeneratedFrontmatter);
							// 	await this.app.vault.modify(file, modifiedContent);
							// } else {
							// 	for (const [key, value] of frontmatter){
							// 		if (frontmatterDefinition.getEntryType(key) === EntryType.TemplateString) {
							// 			frontmatter.set(key, new TemplateString(frontmatterDefinition.getDefaultValue(key)).interpolate({
							// 				title: file.basename,
							// 				titleHash: this.generate_random_sha1(file.basename)
							// 			}))
							// 		}
							// 	}
							// }
							// let content = await this.app.vault.read(file) || '';
							// if (!/---\n[\S\s]*?---\n/.test(content)){
							// 	const frontmatterMap = this.generateNewFrontmatter(file);
							// 	const modifiedContent = await this.appendToContent(file, frontmatterMap);
							// 	//@ts-ignored
							// 	this.app.vault.modify(file, modifiedContent);
							// }
						}
					} catch (error) {
						console.error(error);
						this.modifyFlag = true;
					} finally {
						// this.modifyFlag = true;
						console.log('inside on create frontmatter plugin modify finally block.');
					}
				}
			}));
		});

		this.registerEvent(this.app.vault.on('rename', async (file, oldPath) => {
			const frontmatterDefinition = this.getClosestFrontmatterDefinition(file.path);

			if (file instanceof TFile && file.extension === "md" && frontmatterDefinition) {
				try {
					if (this.modifyFlag) {
						const activeFile = await this.app.workspace.getActiveFile();
						if (!activeFile) return;

						let frontmatter;
						const newGeneratedFrontmatter = this.generateNewFrontmatter(file);
						const existingFrontmatter = await this.getExistingFrontmatter(file);
						if (existingFrontmatter.size > 0) {
							frontmatter = this.mergeWithFrontmatter(newGeneratedFrontmatter, existingFrontmatter);
						} else {
							frontmatter = newGeneratedFrontmatter;
						}

						for (const [key, value] of frontmatter) {
							if (frontmatterDefinition.getEntryType(key) === EntryType.TemplateString) {
								frontmatter.set(key, new TemplateString(frontmatterDefinition.getDefaultValue(key)).interpolate({
									title: file.basename,
									titleHash: this.generate_random_sha1(file.basename)
								}))
							}
						}

						const content = await this.appendToContent(file, frontmatter);
						this.modifyFlag = false;
						this.app.vault.modify(file, content);
						this.modifyFlag = true;
					}
				} catch (error) {
					console.error(error);
					this.modifyFlag = true;
				} finally {
					// this.modifyFlag = true;
					console.log('inside on rename frontmatter plugin modify finally block.');
				}
			}
		}));

		this.registerEvent(this.app.vault.on('modify', async (file) => {
			const frontmatterDefinition = this.getClosestFrontmatterDefinition(file.path);
			if (file instanceof TFile && file.extension === "md" && frontmatterDefinition) {
				try {
					if (this.modifyFlag) {
						// const mmap = await this.getFrontmatterFromFile(file);
						// console.log(mmap);

						this.modifyFlag = false;
						const activeFile = await this.app.workspace.getActiveFile();
						if (!activeFile) return;

						let frontmatter = await this.getFrontmatterFromFile(file); // JM：有一定概率在调用这句时跳到finally，如果在finally块中添加this.modifyFlag=true会导致死循环。穿透后主要是let content = await this.app.vault.read(file) || '';会跳转到finally
						frontmatter.set("modified", moment(new Date()).format('YYYY-MM-DD HH:mm:ss'));
						const content = await this.appendToContent(file, frontmatter);
						await this.app.vault.modify(file, content);
						this.modifyFlag = true;
						// let content = await this.app.vault.read(file) || '';
						// // let frontmatterText = this.getExistingFrontmatter(file);
						// let frontmatterTextMatches = content.match(/---\n[\S\s]*?---\n/);
						//
						// if (frontmatterTextMatches && frontmatterTextMatches.length > 0) {
						// 	// frontmatterMap.set("modified", new Date());
						// 	// let frontmatterText = this.convertToFrontmatterText(frontmatterMap);
						// 	let frontmatterText = frontmatterTextMatches[0];
						// 	if (frontmatterText.indexOf("modified: ") != -1) {
						// 		frontmatterText = frontmatterText.replace(/modified: [\S\s]*?\n/, "modified: " + moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + "\n");
						// 	} else {
						// 		const insertIndex = frontmatterText.lastIndexOf("---");
						// 		frontmatterText = frontmatterText.slice(0, insertIndex) + "modified: " + moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + "\n" + frontmatterText.slice(insertIndex);
						// 	}
						// 	// let content = await this.app.vault.read(file) || '';
						// 	content = content.replace(/---\n[\S\s]*?---\n/, frontmatterText);
						// 	// const content = await this.appendToContent(file, frontmatterMap);
						// 	//@ts-ignored
						// 	await this.app.vault.modify(file, content);
						// }

						// text = this.appendFrontmatter(text, frontmatter);
					}
				} catch (error) {
					console.error(error);
					this.modifyFlag = true;
				} finally {
					// this.modifyFlag = true;
					console.log('inside on modify frontmatter plugin modify finally block.');
				}
			}
		}));
		// this.addCommand({
		// 	id: "test-frontmatter",
		// 	name: "Test Frontmatter",
		// 	icon: "plus-square",
		// 	callback: async () => {
		// 		const noteFrontmatterDefinitions = JSON.parse(this.settings.definitionJsonText);
		// 		console.log(noteFrontmatterDefinitions);
		// 		for (const definition of noteFrontmatterDefinitions){
		// 			const normalNoteFrontmatter = new FrontmatterDefinition(definition.Name);
		// 			for (const attribute of definition.Attributes) {
		// 				//@ts-ignore
		// 				normalNoteFrontmatter.add(attribute.Key, <EntryType>EntryType[attribute.Type], attribute.DefaultValue);
		// 			}
		// 			this.settings.definitionArray.push(normalNoteFrontmatter);
		// 		}
		// 		// const noteFrontmatterDefinitions = [
		// 		// 	{
		// 		// 		Name: "NormalNote",
		// 		// 		Attributes: [
		// 		// 			{Key: "id", Type: "TemplateString", DefaultValue: "${title}_${titleHash}"},
		// 		// 			{Key: "date", Type: "Date", DefaultValue: "${now}"}, // ${now} or "YYYY-MM-DD HH:mm:ss"
		// 		// 			{Key: "source", Type: "String", DefaultValue: "自己的经验"},
		// 		// 			{Key: "tags", Type: "ArrayOfString", DefaultValue: ""}, // split by ,
		// 		// 			{Key: "comments", Type: "String", DefaultValue: ""},
		// 		// 		]
		// 		// 	},
		// 		// 	{
		// 		// 		Name: "BlogNote",
		// 		// 		Attributes: [
		// 		// 			{Key: "id", Type: "TemplateString", DefaultValue: "${title}_${titleHash}"},
		// 		// 			{Key: "date", Type: "Date", DefaultValue: "${now}"}, // ${now} or "YYYY-MM-DD HH:mm:ss"
		// 		// 			{Key: "source", Type: "String", DefaultValue: "自己的经验"},
		// 		// 			{Key: "tags", Type: "ArrayOfString", DefaultValue: ""}, // split by ,
		// 		// 			{Key: "categories", Type: "String", DefaultValue: ""},
		// 		// 			{Key: "series", Type: "String", DefaultValue: ""},
		// 		// 			{Key: "comments", Type: "String", DefaultValue: ""},
		// 		// 		]
		// 		// 	},
		// 		// ]
		// 	},
		// });
		this.addCommand({
			id: "refresh-frontmatter",
			name: "Refresh Frontmatter",
			icon: "plus-square",
			callback: async () => {
				const activeFile = this.app.workspace.getActiveFile();
				if (!activeFile) return;
				const frontmatterDefinition = this.getClosestFrontmatterDefinition(activeFile.path);
				if (activeFile instanceof TFile && activeFile.extension === "md" && frontmatterDefinition) {

					let frontmatter = await this.getExistingFrontmatter(activeFile);
					if (frontmatter.size > 0) {
						for (const [key, value] of frontmatter){
							if (frontmatterDefinition.getEntryType(key) === EntryType.TemplateString) {
								frontmatter.set(key, new TemplateString(frontmatterDefinition.getDefaultValue(key)).interpolate({
									title: activeFile.basename,
									titleHash: this.generate_random_sha1(activeFile.basename)
								}))
							}
						}
					} else {
						frontmatter = this.generateNewFrontmatter(activeFile);
					}

					const content = await this.appendToContent(activeFile, frontmatter);
					this.app.vault.modify(activeFile, content);
				}
			},
		});

        // add settings tab
        this.addSettingTab(new SettingTab(this.app, this));
    }

	parseFrontmatterTextToMap(text: string) {
		const lines = text.split('\n');
		const map = new Map();
		const separator = ": ";
		for (const line of lines) {
			if (line.trim() === '') continue;
			const separatorIndex = line.indexOf(separator);
			if (separatorIndex !== -1) {
				const key = line.slice(0, separatorIndex);
				const value = line.slice(separatorIndex + separator.length);
				const trimmedKey = key.trim();
				let trimmedValue = value ? value.trim() : '';
				if (trimmedValue.startsWith("[")) {
					const validJsonString = trimmedValue.replace(/([^[\]", ]+)/g, '"$1"');
					trimmedValue = JSON.parse(validJsonString);
				}
				map.set(trimmedKey, trimmedValue);
			}
		}
		return map;
	}
	async getFrontmatterTextFromFile(file: TFile) {
		let content = await this.app.vault.read(file) || '';

		let frontmatterTextMatches = content.match(/---\n[\S\s]*?---\n/);
		if (frontmatterTextMatches && frontmatterTextMatches.length > 0) {
			return frontmatterTextMatches[0];
		} else {
			return "";
		}
	}
	async getFrontmatterFromFile(file: TFile) {
		const frontmatterText = await this.getFrontmatterTextFromFile(file);
		if (frontmatterText !== "") {
			return this.parseFrontmatterTextToMap(frontmatterText);
		} else {
			return new Map();
		}
		// let content = await this.app.vault.read(file) || '';
		//
		// let frontmatterTextMatches = content.match(/---\n[\S\s]*?---\n/);
		// if (frontmatterTextMatches && frontmatterTextMatches.length > 0) {
		// 	const frontmatterText = frontmatterTextMatches[0];
		// 	return this.parseFrontmatterTextToMap(frontmatterText);
		// } else {
		// 	return new Map();
		// }
	}

	async getFrontmatterPositionFromFile(file: TFile) {

	}

	async getExistingFrontmatter(file: TFile): Promise<Map<string, string | Array<string> | boolean | number | Date>> {
		return await this.getFrontmatterFromFile(file);
		// return frontmatterMap;
		// let frontmatterMap = null;
		// if (this.app.metadataCache.getCache(file.path).frontmatter) {
		// 	frontmatterMap = new Map<string, string | Array<string> | boolean | number | Date>(Object.entries(this.app.metadataCache.getCache(file.path).frontmatter));
		// }
		// return frontmatterMap;
	}

	generateNewFrontmatter(file: TFile): Map<string, string | Array<string> | boolean | number | Date> {
		const frontmatterDefinition = this.getClosestFrontmatterDefinition(file.path);
		const frontmatter = new Map();
		if (frontmatterDefinition) {
			for (const [key, entryType, defaultValue] of frontmatterDefinition.iter()) {
				if (entryType === EntryType.TemplateString) {
					frontmatter.set(key, new TemplateString(defaultValue).interpolate({
						title: file.basename,
						titleHash: this.generate_random_sha1(file.basename)
					}));
				} else if (entryType === EntryType.Date) {
					if ((<string>defaultValue).toLowerCase().trim() === "${now}") {
						frontmatter.set(key, new Date());
					} else {
						frontmatter.set(key, new Date(<string>defaultValue));
					}
				} else if (entryType === EntryType.ArrayOfString) {
					frontmatter.set(key, (<string>defaultValue).split(",").map(item => item.trim()));
				} else {
					frontmatter.set(key, defaultValue);
				}
			}
		}
		return frontmatter;
	}

	mergeWithFrontmatter(frontmatter1: Map<string, string | Array<string> | boolean | number | Date>, frontmatter2: Map<string, string | Array<string> | boolean | number | Date>): Map<string, string | Array<string> | boolean | number | Date> {
		for (const key of frontmatter1.keys()){
			if (frontmatter2.has(key)){
				frontmatter1.set(key, frontmatter2.get(key));
			}
		}
		return frontmatter1;
		// return new Map([...frontmatter1, ...frontmatter2]);
	}

	parseDefinitionJsonTextSetting() {
		try {
			this.settings.definitionArray = [];
			for (const namedJsonText of this.settings.definitionNamedJsonTextArray) {
				const normalNoteFrontmatter = new FrontmatterDefinition(namedJsonText.name);
				const attributes = JSON.parse(namedJsonText.jsonText);
				for (const attribute of attributes) {
					//@ts-ignore
					normalNoteFrontmatter.add(attribute.Key, <EntryType>EntryType[attribute.Type], attribute.DefaultValue);
				}
				this.settings.definitionArray.push(normalNoteFrontmatter);
			}
		} catch (ex){
			console.error("parse json failed, please configure in setting.");
		}
	}
    async loadSettings() {
        this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
		this.parseDefinitionJsonTextSetting();

		// const normalNoteFrontmatter = new FrontmatterDefinition("NormalNote");
		// normalNoteFrontmatter.add("id", EntryType.TemplateString, "${title}_${titleHash}");
		// normalNoteFrontmatter.add("date", EntryType.Date, new Date());
		// normalNoteFrontmatter.add("source", EntryType.String, "自己的经验");
		// normalNoteFrontmatter.add("tags", EntryType.ArrayOfString, []);
		// normalNoteFrontmatter.add("comments", EntryType.String, "");
		// this.settings.definitionArray.push(normalNoteFrontmatter);
		//
		// const blogNoteFrontmatter = new FrontmatterDefinition("BlogNote");
		// blogNoteFrontmatter.add("id", EntryType.TemplateString, "${title}_${titleHash}");
		// blogNoteFrontmatter.add("date", EntryType.Date, new Date());
		// blogNoteFrontmatter.add("source", EntryType.String, "自己的经验");
		// blogNoteFrontmatter.add("tags", EntryType.ArrayOfString, []);
		// blogNoteFrontmatter.add("categories", EntryType.ArrayOfString, []);
		// blogNoteFrontmatter.add("series", EntryType.ArrayOfString, []);
		// blogNoteFrontmatter.add("comments", EntryType.String, "");
		// this.settings.definitionArray.push(blogNoteFrontmatter);
    }

    async saveSettings() {
        await this.saveData(this.settings);
		this.parseDefinitionJsonTextSetting();
    }

	async appendToContent(file: TFile, frontmatter: Map<string, string | Array<string> | boolean | number | Date>): Promise<string> {
		let content = await this.app.vault.read(file) || '';
		if (content.startsWith("---")) {
			// 如果已存在frontmatter，则先去掉
			// const frontmatterText = await this.getFrontmatterTextFromFile(file);
			content = content.replace(/---\n[\S\s]*?---\n/, ""); // JM：这里会在文本开始处多一个换行
			// const insertIndex = frontmatterText.lastIndexOf("---");
			// const newFrontmatterText = frontmatterText.slice(0, insertIndex) + "modified: " + moment(new Date()).format('YYYY-MM-DD HH:mm:ss') + "\n" + frontmatterText.slice(insertIndex);
		}
		const frontmatterText = this.convertToFrontmatterText(frontmatter);
		return `${frontmatterText}${content}`;


		// let content = await this.app.vault.read(file) || '';
		// if (this.app.metadataCache.getCache(file.path) && this.app.metadataCache.getCache(file.path).frontmatter) {
		// 	const frontmatterPosition = this.app.metadataCache.getCache(file.path).frontmatterPosition;
		// 	const originalFrontMatterText = content.substring(frontmatterPosition.start.offset, frontmatterPosition.end.offset);
		// 	content = content.replace(originalFrontMatterText, "").trim();
		// }
		// const frontmatterText = this.convertToFrontmatterText(frontmatterMap);
		// return `${frontmatterText}${content}`;
	}
	convertToFrontmatterText(frontmatter: Map<string, string | Array<string> | boolean | number | Date>): string {
		let frontmatterText = "";
		const props = Object.keys(frontmatter);

		for (let key of frontmatter.keys()) {
			let frontmatterItem = frontmatter.get(key);
			if (!frontmatterItem){
				frontmatterItem = "";
			} else if (frontmatterItem instanceof Array){
				// const tempArray = metadataValue.map((item) => {
				// 	return `'${item}'`;
				// });
				frontmatterItem = `[${frontmatterItem.join(",")}]`;
			} else if (typeof frontmatterItem === 'string') {
				frontmatterItem = `${frontmatterItem}`;
			} else if (frontmatterItem instanceof Date) {
				//@ts-ignored
				frontmatterItem = moment(frontmatterItem).format("YYYY-MM-DD HH:mm:ss");
			} else {
				frontmatterItem = frontmatterItem.toString();
			}
			frontmatterText += `${key}: ${frontmatterItem}\n`
		}
		return `---\n${frontmatterText}---\n`;
	}

	generate_random_sha1(text: string) {
		const crypto = require('crypto');
		if (text) {
			return crypto.createHash('sha1').update(text).digest('hex');
		}
		const current_date = (new Date()).valueOf().toString();
		const random = Math.random().toString();
		return crypto.createHash('sha1').update(current_date + random).digest('hex');
	}
}

class SettingTab extends PluginSettingTab {
    plugin: FrontMatterManagerPlugin;

    constructor(app: App, plugin: FrontMatterManagerPlugin) {
        super(app, plugin);
        this.plugin = plugin;
    }

	arraymove<T>(
		arr: T[],
		fromIndex: number,
		toIndex: number
	): void {
		if (toIndex < 0 || toIndex === arr.length) {
			return;
		}
		const element = arr[fromIndex];
		arr[fromIndex] = arr[toIndex];
		arr[toIndex] = element;
	}

	display(): void {
        const {containerEl} = this;
        containerEl.empty();

        this.containerEl.createEl("h2", { text: "PathMap setting." });
        const desc = document.createDocumentFragment();
        desc.append(
            "Define path name mapping. name is the key link with frontmatter attributes definition."
        );
		new Setting(this.containerEl).setDesc(desc);

		this.plugin.settings.pathNameArray.forEach((item, index) => {
			const s = new Setting(this.containerEl)
				.addText(text => text
					.setPlaceholder("1_Inbox/Diary/")
					.setValue(this.plugin.settings.pathNameArray[index].pathPrefix)
					.onChange(async (value) => {
						this.plugin.settings.pathNameArray[index].pathPrefix = value;
						await this.plugin.saveSettings();
					}))
				.addText(text => text
					.setPlaceholder("")
					.setValue(this.plugin.settings.pathNameArray[index].name)
					.onChange(async (value) => {
						this.plugin.settings.pathNameArray[index].name = value;
						await this.plugin.saveSettings();
					}))
				.addExtraButton((cb) => {
				    cb.setIcon("up-chevron-glyph")
				        .setTooltip("Move up")
				        .onClick(() => {
				            this.arraymove(
								this.plugin.settings.pathNameArray,
				                index,
				                index - 1
				            );
				            this.plugin.saveSettings();
				            this.display();
				        });
				})
				.addExtraButton((cb) => {
				    cb.setIcon("down-chevron-glyph")
				        .setTooltip("Move down")
				        .onClick(() => {
				            this.arraymove(
								this.plugin.settings.pathNameArray,
				                index,
				                index + 1
				            );
				            this.plugin.saveSettings();
				            this.display();
				        });
				})
				.addExtraButton((cb) => {
					cb.setIcon("cross")
						.setTooltip("Delete")
						.onClick(() => {
							this.plugin.settings.pathNameArray.splice(index, 1);
							this.plugin.saveSettings();
							// Force refresh
							this.display();
						});
				});
		});
		new Setting(this.containerEl).addButton((cb) => {
			cb.setButtonText("Add")
				.setCta()
				.onClick(() => {
					this.plugin.settings.pathNameArray.push({pathPrefix: "1", name: "2"});
					this.plugin.saveSettings();
					// Force refresh
					this.display();
				});
		});

		this.containerEl.createEl("h2", { text: "Attributes setting." });
		const desc2 = document.createDocumentFragment();
		desc2.append(
			`Define the frontmatter attributes.
			 EnumType: TemplateString, String, ArrayOfString, Number, Boolean, Date
			 DefaultValue: TemplateString-> \${title}, \${titleHash}
			               Date -> \${now} or YYYY-MM-DD HH:mm:ss 
			`
		);
		new Setting(this.containerEl).setDesc(desc2);
		this.plugin.settings.definitionNamedJsonTextArray.forEach((item, index) => {
			const s = new Setting(this.containerEl)
				.addText(text => text
					.setPlaceholder("")
					.setValue(this.plugin.settings.definitionNamedJsonTextArray[index].name)
					.onChange(async (value) => {
						this.plugin.settings.definitionNamedJsonTextArray[index].name = value;
						await this.plugin.saveSettings();
					}))
				.addTextArea(textArea => {
					textArea
						.setPlaceholder("[]")
						.setValue(this.plugin.settings.definitionNamedJsonTextArray[index].jsonText)
						.onChange(async (value) => {
							this.plugin.settings.definitionNamedJsonTextArray[index].jsonText = value;
							await this.plugin.saveSettings();
						});
					textArea.inputEl.cols = 55;
					textArea.inputEl.rows = 5;
				})
				.addExtraButton((cb) => {
					cb.setIcon("up-chevron-glyph")
						.setTooltip("Move up")
						.onClick(() => {
							this.arraymove(
								this.plugin.settings.definitionNamedJsonTextArray,
								index,
								index - 1
							);
							this.plugin.saveSettings();
							this.display();
						});
				})
				.addExtraButton((cb) => {
					cb.setIcon("down-chevron-glyph")
						.setTooltip("Move down")
						.onClick(() => {
							this.arraymove(
								this.plugin.settings.definitionNamedJsonTextArray,
								index,
								index + 1
							);
							this.plugin.saveSettings();
							this.display();
						});
				})
				.addExtraButton((cb) => {
					cb.setIcon("cross")
						.setTooltip("Delete")
						.onClick(() => {
							this.plugin.settings.definitionNamedJsonTextArray.splice(index, 1);
							this.plugin.saveSettings();
							// Force refresh
							this.display();
						});
				});
		});
		new Setting(this.containerEl).addButton((cb) => {
			cb.setButtonText("Add")
				.setCta()
				.onClick(() => {
					this.plugin.settings.definitionNamedJsonTextArray.push({name: "", jsonText: "{}"});
					this.plugin.saveSettings();
					// Force refresh
					this.display();
				});
		});
    }
}
